﻿/* 
 * Copyright 2010 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ngilead.Core.Exception;
using System.Collections;
using System.Reflection;

namespace Ngilead.Core.Replicator
{
    /// <summary>
    /// Replicator for dictionary properties
    /// </summary>
    public class DictionaryReplicator : AbstractReplicator
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public DictionaryReplicator() 
        { }

        #endregion

        #region Public interface

        /// <summary>
        /// Create a clone of the argument dictionary
        /// </summary>
        /// <typeparam name="T">IDictionary</typeparam>
        /// <param name="from">The input dictionary</param>
        /// <returns>The replicated dictionary</returns>
        public virtual T ReplicateDictionary<T>(T from) where T : IDictionary
        {
            T toDictionary;
            try
            {
                toDictionary = CreateToDictionary(from);

                PutTargetCloned(from, toDictionary);
                // recursively populate member objects.
                foreach (Object fromKey in from.Keys)
                {
                    //  Clone key
                    //
                    object cloneKey;
                    if (fromKey == null)
                    {
                        Type GType = from.GetType().GetGenericArguments()[0];
                        cloneKey = GType.IsValueType ? Activator.CreateInstance(GType) : null;
                    }
                    else
                        cloneKey = BeanTransformer.Replicate(fromKey);

                    //  Clone value
                    //
                    object cloneValue;
                    object fromValue = from[fromKey];
                    if (fromValue == null)
                    {
                        //V cloneValue = default(V);
                        Type VType = from.GetType().GetGenericArguments()[1];
                        cloneValue = VType.IsValueType ? Activator.CreateInstance(VType) : null;
                    }
                    else
                        cloneValue = BeanTransformer.Replicate(fromValue);

                    toDictionary.Add(cloneKey, cloneValue);
                }
            }
            catch (System.Exception e)
            {
                throw new CloneException(e.Message, e);
            }
            return toDictionary;
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Create a new (empty) dictionary of the same type as the argument
        /// </summary>
        /// <typeparam name="T">IDictionary</typeparam>
        /// <param name="from">The input dictionary</param>
        /// <returns>The new empty dictionary</returns>
        protected virtual T CreateToDictionary<T>(T from) where T : IDictionary
        {
            return CollectionUtil.CreateToDictionary(from);
        }

        #endregion
    }
}
